package local

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"time"
)

type LocFormTime time.Time

func (t *LocFormTime) UnmarshalParam(src string) error {
	ts, err := time.Parse("2006-01-02", src)
	*t = LocFormTime(ts)
	return err
}

/*
	自定义格式:
		LocalDate "2006-01-02" 能正确接受 null 和 返回 null
			LocalData{Time: time.Time}
		LocalDatetime "2006-01-02 15:04:05" 能正确接受 null 和 返回 null
			LocalDatatime{Time: time.Time}
*/

/* ------
	自定义时间格式 date(yyyy-MM-dd)
	如: 前端发起请求 新增数据 或 获取数据。调用流程为:
		client -> (UnmarshalJSON) server (Value) -> mysql;
		mysql -> (Scan) server (MarshalJSON) -> client;
	新建: LocalDate{Time: time.Time}
------ */

// LocalDate 自定义时间 yyyy-MM-dd。如果时间为空,存储到数据库 和 编码返回前端也会为空。
type LocalDate struct {
	time.Time
}

// UnmarshalJSON 将 json 字符串解码成 LocalDate 时调用。 client -> server
func (t *LocalDate) UnmarshalJSON(b []byte) error {
	m := make(map[string]interface{}) // 如果前端传的参数为 null。b 大概长这样 [110 117 108 108], 解码出来的 map 为 map[]
	err := json.Unmarshal(b, &m)
	if err != nil {
		str := string(b[1 : len(b)-1]) // json 编码 "2020" len() 是 4,会变成 ""2020"" len() 是 6,多了两个 "
		tm, err1 := StrToTime(str)
		if err1 == nil {
			*t = LocalDate{Time: tm}
		}
		return err1
	}
	return nil
}

// MarshalJSON 将 LocalDate 编码成 json 字符串时调用。 server -> client
func (t LocalDate) MarshalJSON() ([]byte, error) {
	if t.Year() == 1 { // 数据库 date 值为空时,转化后默认值是 0001-01-01 00:00:00 +0000 UTC, 如果是默认值就返回 nil
		m, err := json.Marshal(nil)
		return m, err
	}
	str := fmt.Sprintf("\"%s\"", t.Format(FormatDay))
	return []byte(str), nil
}

// Value 保存到数据库时调用。sever -> mysql (新增一条会调用两次, 原因未知 TODO)
func (t LocalDate) Value() (driver.Value, error) {
	if t.Year() == 1 { // 后默认值是 0001-01-01 00:00:00 +0000 UTC, 如果是默认值就返回 nil
		return nil, nil
	}
	return t.Format(FormatDay), nil
}

// Scan 接受数据库数据时调用。mysql -> server。有值时才会调用,如有三条数据,只有一条有值 date 不为 null,会调用一次。
func (t *LocalDate) Scan(v interface{}) error {
	value, ok := v.(time.Time)
	if ok {
		*t = LocalDate{Time: value}
		return nil
	}
	return fmt.Errorf("LocalDate: can not convert %v to date", v)
}

/* ------ 自定义时间格式 datetime(yyyy-MM-dd) ------ */

// LocalDatetime 自定义时间 yyyy-MM-dd HH:MM:SS。如果时间为空,存储到数据库 和 编码返回前端也会为空。
type LocalDatetime struct {
	time.Time
}

// UnmarshalJSON 将 json 字符串解码成 LocalDate 时调用。 client -> server
func (t *LocalDatetime) UnmarshalJSON(b []byte) error {
	m := make(map[string]interface{}) // 如果前端传的参数为 null。b 大概长这样 [110 117 108 108], 解码出来的 map 为 map[]
	err := json.Unmarshal(b, &m)
	if err != nil {
		str := string(b[1 : len(b)-1]) // json 编码 "2020" len() 是 4,会变成 ""2020"" len() 是 6,多了两个 "
		tm, err1 := StrToTime(str)
		if err1 == nil {
			*t = LocalDatetime{Time: tm}
		}
		return err1
	}
	return err
}

// MarshalJSON 将 LocalDate 编码成 json 字符串时调用。 server -> client
func (t LocalDatetime) MarshalJSON() ([]byte, error) {
	if t.Year() == 1 { // 数据库 date 值为空时,转化后默认值是 0001-01-01 00:00:00 +0000 UTC, 如果是默认值就返回 nil
		m, err := json.Marshal(nil)
		return m, err
	}
	str := fmt.Sprintf("\"%s\"", t.Format(FormatSec)) // json.Marshal() 也可以
	return []byte(str), nil
}

// Value 保存到数据库时调用。sever -> mysql (新增一条会调用两次, 原因未知 TODO)
func (t LocalDatetime) Value() (driver.Value, error) {
	if t.Year() == 1 { // 后默认值是 0001-01-01 00:00:00 +0000 UTC, 如果是默认值就返回 nil
		return nil, nil
	}
	return t.Format(FormatSec), nil
}

// Scan 接受数据库数据时调用。mysql -> server。有值时才会调用,如有三条数据,只有一条有值 date 不为 null,会调用一次。
func (t *LocalDatetime) Scan(v interface{}) error {
	value, ok := v.(time.Time)
	if ok {
		*t = LocalDatetime{Time: value}
		return nil
	}
	return fmt.Errorf("LocalDatetime: can not convert %v to datetime", v)
}
